#include "cCaenEvent.hh"
#include <stdlib.h>
using namespace std;

//cCaenEvent::cCaenEvent(){
//	lastTimeStamp=0;
//	correctionTime=0;
//};

double cCaenEvent::lastTimestamp;
double cCaenEvent::correctionTime;

ostream& operator<< (ostream& output, const cCaenEvent& p){
        cout<<"energy is "<<p.energy<<"  "<<p.timestamp<<"  "<<p.trigId<<"  "<<p.detNr;
		return output;
}

istream& operator>> (istream& input, cCaenEvent& p){
        if(input>>p.detNr>>p.timestamp>>p.trigId>>p.energy){
			p.isPileUp=(p.detNr)/16; 
			p.detNr=(p.detNr)%16;
			p.energy=p.energy*(-1);
			//cout<<p.timestamp<<"  "<<endl;
			p.timestamp=p.timestamp/100./1000./1000.; //(sec)
			if(cCaenEvent::lastTimestamp - 1 >p.timestamp){   //if there is a reset, the difference should be higher than 1 sec
				cCaenEvent::correctionTime=p.correctionTime + 2814749.76710656;
				cout<<"                                        timestamp reset detected; applying correction;"<<endl;
				cout<<"                                                       "<<cCaenEvent::lastTimestamp<<" timestamp "<<p.timestamp<<endl;

				exit(1);//cout<<p.detNr<<endl;
			};
			//cout<<cCaenEvent::lastTimestamp<<"     timestamp  "<<p.timestamp<<endl;	
			cCaenEvent::lastTimestamp=p.timestamp;	
			//cout<<cCaenEvent::lastTimestamp<<endl;
			p.timestamp=p.timestamp+cCaenEvent::correctionTime;
			
			//cout.width(27);
			//cout.precision(13);
			//cout<<p.timestamp*100000000<<"  "<<p.timestamp<<endl;
		
			//! the timestamp re0initialisation feature (pg 107 in TNT_functionalities.pdf): the timestamp counter is rest when the counter goes over 48 bits max value: 281 474 976 710 656 0 = 32.5 days
		
			//! confirmed with the u230 experiment: 
			//    281474976710656
			//	2 281474515389575 14968696 -4523
			//  2 281474515414802 14968697 -4933
			//! 2 281474744941036 14968698 -3994
			//! 2       118981888 14968699 -3712
			//! 2       158328282 14968700 -3711

			p.isDead=0;
		};	
        return input;
}

int cCaenEvent::DecodeFromBinary(uint8_t buffer[16]) {
	timestamp = detNr = energy = trigId = isPileUp = 0;
	unsigned long long int time=0;
	int evEnergy=0;
	int i;
	for (i = 0; i < 6; i++) {
		time += buffer[i];
		time <<= 8; // shifts to the left with 8 bits. See "Bitwise operations in C"
	}time>>=8;
	for(int i=6;i<10;i++){
		trigId += buffer[i];
		trigId <<= 8;
		//cout<<std::hex<<buffer[i]<<endl;
	}; trigId>>=8;

	evEnergy += buffer[10];
	evEnergy <<= 8;
	evEnergy += buffer[11];
	//chNo=buffer[12];
	detNr = buffer[13];
	if (detNr > 16) {
		detNr = detNr - 16;
		isPileUp = 1;
	};
	timestamp = time;
	energy=evEnergy;
	evEnergy=0;
	timestamp=timestamp/100./1000./1000.; //(sec)
				if(timestamp>0) if(cCaenEvent::lastTimestamp - 1 >timestamp){   //if there is a reset, the difference should be higher than 1 sec
					cCaenEvent::correctionTime=correctionTime + 2814749.76710656;
					cout<<"                                        timestamp reset detected; applying correction;"<<endl;
					cout<<"                                                       "<<cCaenEvent::lastTimestamp<<" timestamp "<<timestamp<<endl;
					//cout<<p.detNr<<endl;
					exit(1);
				};
				//cout<<cCaenEvent::lastTimestamp<<"     timestamp  "<<p.timestamp<<endl;
				cCaenEvent::lastTimestamp=timestamp;
				//cout<<cCaenEvent::lastTimestamp<<endl;
				timestamp=timestamp+cCaenEvent::correctionTime;
	cout<<timestamp<<"  "<<time<<"   "<<detNr<<"  "<<trigId<<"  "<<isPileUp<<"  "<<energy<<"\n";
	//additional += buffer[12]; additional <<= 8; additional += buffer[13];
	return 0;
}
;
int cCaenEvent::Set(unsigned long long ptimestamp, int penergy, int ptrigId,
		int pchannel) {
	timestamp = detNr = energy = trigId = isPileUp = realEnergy=0;
	timestamp = ptimestamp / 100. / 1000. / 1000.; //(sec)
	energy = realEnergy=penergy;
	trigId = ptrigId;
	detNr = pchannel;
	isPileUp=0;
//	if (detNr > 16) {
//		//cout<<*this<<endl;
//		detNr = detNr - 16;
//		isPileUp = 1;
//
//	};
//	if (detNr > 21) {
//			cout<<*this<<endl;
//			//detNr = detNr - 16;
//			//isPileUp = 1;
//
//		};
	if (timestamp > 0)
		if (cCaenEvent::lastTimestamp - 1 > timestamp) { //if there is a reset, the difference should be higher than 1 sec
			cCaenEvent::correctionTime = correctionTime + 2814749.76710656;
			cout
					<< "                                        timestamp reset detected; applying correction;"
					<< endl;
			cout << "                                                       "
					<< cCaenEvent::lastTimestamp << " timestamp " << timestamp
					<< endl;
			exit(1);
			//cout<<p.detNr<<endl;
		};
	//cout<<cCaenEvent::lastTimestamp<<"     timestamp  "<<p.timestamp<<endl;
	cCaenEvent::lastTimestamp = timestamp;
	//cout<<cCaenEvent::lastTimestamp<<endl;
	timestamp = timestamp + cCaenEvent::correctionTime;
	//cout << timestamp << "  " << time << "   " << detNr << "  " << trigId;
	//cout << "  " << isPileUp << "  " << energy << "\n";
	return 1;
}
;
